/*
 * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "napi_file_share.h"
#include "napi_file_share_util.h"
#include "share_manager.h"
#include "string_ex.h"
#include "device_manager.h"
#include "dm_constants.h"
#include "dm_device_info.h"
#include "ipc_skeleton.h"
#include "js_native_api.h"
#include "tokenid_kit.h"
#include "nlohmann/json.hpp"
#include <thread>
#include <chrono>
#include <random>
using namespace OHOS::DistributedHardware;

namespace OHOS {
namespace FileShare {
namespace {
#define GET_PARAMS(env, info, num)                                                                                     \
    size_t argc = num;                                                                                                 \
    napi_value argv[num] = {nullptr};                                                                                  \
    napi_value thisVar = nullptr;                                                                                      \
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr))

const int32_t FS_NAPI_ARGS_ZERO = 0;
const int32_t FS_NAPI_ARGS_ONE = 1;
const int32_t FS_NAPI_ARGS_TWO = 2;
const int32_t FS_NAPI_ARGS_THREE = 3;
const int32_t PUBLISH_ID = 4082;
const uint16_t MAX_RANDOM = 65535;
const std::string BUNDLE_NAME = "com.ohos.oneconnect.share";

const std::string FS_NAPI_EVENT_DEVICE_CONNECTION_CHANGE = "connectionChange";
const std::string FS_NAPI_EVENT_DEVICE_DISCOVER_SUCCESS = "discoverSuccess";
const std::string FS_NAPI_EVENT_DEVICE_DISCOVER_FAIL = "discoverFailure";
const std::string FS_NAPI_EVENT_DEVICE_PUBLISH_SUCCESS = "publishSuccess";
const std::string FS_NAPI_EVENT_DEVICE_PUBLISH_FAIL = "publishFailure";
const std::string FS_NAPI_EVENT_SHARE_STATUS_CHANGE = "shareStatusChange";
const std::string FS_NAPI_EVENT_DEVICE_SERVICE_DIE = "serviceDie";
const std::string FS_NAPI_EVENT_SEND_CHANGE = "sendChange";
const std::string FS_NAPI_AUTH_STATE_CHANGE = "authStateChange";

std::map<std::string, NapiFileShare *> g_fileShareMap;
std::map<std::string, std::shared_ptr<FSNapiPublishCallback>> g_publishCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiDiscoveryCallback>> g_DiscoveryCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiInitCallback>> g_initCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiAuthenticateCallback>> g_authCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiDeviceStatusCallback>> g_deviceStatusCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiSendFileCallback>> g_sendFileCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiUiCallback>> g_uiCallbackMap;
std::map<std::string, std::shared_ptr<FSNapiShareStatusCallback>> g_shareStatusCallbackMap;

std::mutex g_fileShareMapMutex;
std::mutex g_initCallbackMapMutex;
uint16_t g_subscribeId = 0;

void DeleteUvWork(uv_work_t *work)
{
    if (work == nullptr) {
        return;
    }
    delete work;
    work = nullptr;
    LOGD("delete work!");
}

void DeleteFSNapiStatusJsCallbackPtr(FSNapiStatusJsCallback *pJsCallbackPtr)
{
    if (pJsCallbackPtr == nullptr) {
        return;
    }
    delete pJsCallbackPtr;
    pJsCallbackPtr = nullptr;
    LOGD("delete FSNapiStatusJsCallback callbackPtr!");
}

bool IsShareManagerNapiNull(napi_env env, napi_value thisVar, NapiFileShare **pShareManagerWrapper)
{
    napi_unwrap(env, thisVar, reinterpret_cast<void **>(pShareManagerWrapper));
    if (pShareManagerWrapper != nullptr && *pShareManagerWrapper != nullptr) {
        return false;
    }
    CreateBusinessError(env, ERR_CONSTRUCT_FAILED);
    LOGE(" NapiFileShare object is nullptr!");
    return true;
}

uint16_t GenRandUint(uint16_t randMin, uint16_t randMax)
{
    std::random_device randDevice;
    std::mt19937 genRand(randDevice());
    std::uniform_int_distribution<int> disRand(randMin, randMax);
    return disRand(genRand);
}
} // namespace

AuthAsyncCallbackInfo NapiFileShare::authAsyncCallbackInfo_;
thread_local napi_ref NapiFileShare::sConstructor = nullptr;

void FSNapiDeviceStatusCallback::OnDeviceOnline(const DmDeviceBasicInfo &deviceBasicInfo)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiDeviceStatusCallback: OnDeviceOnline, No memory");
        return;
    }

    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, 0, 0, deviceBasicInfo);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnDeviceOnline, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnDeviceStatusChange(FSNapiDevStatusChange::AVAILABLE, callback->deviceBasicInfo_);
        }
        DeleteFSNapiStatusJsCallbackPtr(callback);
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnDeviceOnline work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}

void FSNapiDeviceStatusCallback::OnDeviceReady(const DmDeviceBasicInfo &deviceBasicInfo)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiDeviceStatusCallback: OnDeviceReady, No memory");
        return;
    }

    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, 0, 0, deviceBasicInfo);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnDeviceReady, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnDeviceStatusChange(FSNapiDevStatusChange::AVAILABLE, callback->deviceBasicInfo_);
        }
        DeleteFSNapiStatusJsCallbackPtr(callback);
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnDeviceReady work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}

void FSNapiDeviceStatusCallback::OnDeviceOffline(const DmDeviceBasicInfo &deviceBasicInfo)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiDeviceStatusCallback: OnDeviceOffline, No memory");
        return;
    }

    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, 0, 0, deviceBasicInfo);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnDeviceOffline, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnDeviceStatusChange(FSNapiDevStatusChange::UNAVAILABLE, callback->deviceBasicInfo_);
        }
        DeleteFSNapiStatusJsCallbackPtr(callback);
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnDeviceOffline work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}

void FSNapiDeviceStatusCallback::OnDeviceChanged(const DmDeviceBasicInfo &deviceBasicInfo)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiDeviceStatusCallback: OnDeviceChanged, No memory");
        return;
    }

    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, 0, 0, deviceBasicInfo);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnDeviceChanged, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            std::string deviceName = callback->deviceBasicInfo_.deviceName;
            fileShareNapi->OnDeviceStatusChange(FSNapiDevStatusChange::CHANGE, callback->deviceBasicInfo_);
        }
        DeleteFSNapiStatusJsCallbackPtr(callback);
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnDeviceChanged work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}
void FSNapiAuthenticateCallback::OnAuthResult(const std::string &deviceId, const std::string &token, int32_t status,
                                              int32_t reason)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiAuthenticateCallback::OnAuthResult, No memory");
        return;
    }

    FSNapiAuthJsCallback *jsCallback = new (std::nothrow) FSNapiAuthJsCallback(bundleName_, deviceId, token, status, reason);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiAuthJsCallback *callback = reinterpret_cast<FSNapiAuthJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnAuthResult, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnAuthResult(callback->deviceId_, callback->token_,
                callback->status_, callback->reason_);
        }
        delete callback;
        callback = nullptr;
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnAuthResult work queue");
        delete jsCallback;
        jsCallback = nullptr;
        DeleteUvWork(work);
    }
}

void FSNapiSendFileCallback::OnSending(SendState state, SendInfo &info)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiSendFileCallback::OnSending, No memory");
        return;
    }

    FSNapiSendFileJSCallback *jsCallback = new (std::nothrow) FSNapiSendFileJSCallback(bundleName_, state, info);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiSendFileJSCallback *callback = reinterpret_cast<FSNapiSendFileJSCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnAuthResult, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnSending(callback->state_, callback->info_);
        }
        delete callback;
        callback = nullptr;
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnAuthResult work queue");
        delete jsCallback;
        jsCallback = nullptr;
        DeleteUvWork(work);
    }
}

void FSNapiShareStatusCallback::OnShareStatus(bool shareStatus)
{
    LOGD("FSNapiShareStatusCallback::OnShareStatus, shareStatus %{public}d", shareStatus);
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiSendFileCallback::OnShareStatus, No memory");
        return;
    }

    FSNapiShareStatusJSCallback *jsCallback = new (std::nothrow) FSNapiShareStatusJSCallback(bundleName_, shareStatus);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiShareStatusJSCallback *callback = reinterpret_cast<FSNapiShareStatusJSCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnAuthResult, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnShareStatus(callback->shareStatus_);
        }
        delete callback;
        callback = nullptr;
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnAuthResult work queue");
        delete jsCallback;
        jsCallback = nullptr;
        DeleteUvWork(work);
    }
}

void FSNapiUiCallback::OnCall(const std::string &paramJson)
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiUiCallback: OnCall, No memory");
        return;
    }

    FSNapiUIJsCallback *jsCallback = new FSNapiUIJsCallback(bundleName_, paramJson);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiUIJsCallback *callback = reinterpret_cast<FSNapiUIJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnCall, fileShareNapi not find for bundleName %s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnUiCall(callback->paramJson);
        }
        delete callback;
        callback = nullptr;
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnCall work queue");
        delete jsCallback;
        jsCallback = nullptr;
        DeleteUvWork(work);
    }
}

void FSNapiInitCallback::OnRemoteDied()
{
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiInitCallback: OnRemoteDied, No memory");
        return;
    }

    DmDeviceBasicInfo info;
    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, 0, 0, info);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
        FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
        NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
        if (fileShareNapi == nullptr) {
            LOGE("OnRemoteDied, fileShareNapi not find for bundleName %{public}s", callback->bundleName_.c_str());
        } else {
            fileShareNapi->OnEvent("serviceDie", FS_NAPI_ARGS_ZERO, nullptr);
        }
        LOGI("OnRemoteDied, fileShareNapi bundleName %{public}s", callback->bundleName_.c_str());
        DeleteFSNapiStatusJsCallbackPtr(callback);
        DeleteUvWork(work);
    }, uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnRemoteDied work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}

void FSNapiPublishCallback::OnPublishResult(int32_t publishId, int32_t publishResult)
{
    LOGD("OnPublishResult for %{public}s, publishId %{public}d, publishResult %{public}d", bundleName_.c_str(), publishId, publishResult);
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiPublishCallback: OnPublishResult, No memory");
        return;
    }

    FSNapiPublishJsCallback *jsCallback = new (std::nothrow) FSNapiPublishJsCallback(bundleName_, publishId, publishResult);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(
        loop, work, [](uv_work_t *work) {},
        [](uv_work_t *work, int status) {
            FSNapiPublishJsCallback *callback = reinterpret_cast<FSNapiPublishJsCallback *>(work->data);
            NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
            if (fileShareNapi == nullptr) {
                LOGE("OnPublishResult, fileShareNapi failed for bundleName %{public}s", callback->bundleName_.c_str());
            } else {
                fileShareNapi->OnPublishResult(callback->publishId_, callback->reason_);
            }
            delete callback;
            callback = nullptr;
            DeleteUvWork(work);
        },
        uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnPublishResult work queue");
        delete jsCallback;
        jsCallback = nullptr;
        DeleteUvWork(work);
    }
}

void FSNapiPublishCallback::IncreaseRefCount() { refCount_++; }

void FSNapiPublishCallback::DecreaseRefCount() { refCount_--; }

int32_t FSNapiPublishCallback::GetRefCount() { return refCount_; }

void FSNapiDiscoveryCallback::OnDeviceFound(uint16_t subscribeId, const DmDeviceBasicInfo &deviceBasicInfo)
{
    LOGD("OnDeviceFound for %{public}s, subscribeId %{public}d", bundleName_.c_str(), (int32_t)subscribeId);
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiDiscoveryCallback: OnDeviceFound, No memory");
        return;
    }

    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, subscribeId, 0, deviceBasicInfo);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(
        loop, work, [](uv_work_t *work) {},
        [](uv_work_t *work, int status) {
            FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
            NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
            if (fileShareNapi == nullptr) {
                LOGE("OnDeviceFound, fileShareNapi not find for bundleName %{public}s", callback->bundleName_.c_str());
            } else {
                fileShareNapi->OnDeviceFound(callback->subscribeId_, callback->deviceBasicInfo_);
            }
            DeleteFSNapiStatusJsCallbackPtr(callback);
            DeleteUvWork(work);
        },
        uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnDeviceFound work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}

void FSNapiDiscoveryCallback::OnDiscoveryFailed(uint16_t subscribeId, int32_t failedReason)
{
    LOGD("OnDiscoveryFailed for %{public}s, subscribeId %{public}d", bundleName_.c_str(), (int32_t)subscribeId);

    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(env_, &loop);
    if (loop == nullptr) {
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("FSNapiDiscoveryCallback: OnDiscoveryFailed, No memory");
        return;
    }

    DmDeviceBasicInfo info;
    FSNapiStatusJsCallback *jsCallback = new (std::nothrow) FSNapiStatusJsCallback(bundleName_, subscribeId, failedReason, info);
    if (jsCallback == nullptr) {
        DeleteUvWork(work);
        return;
    }
    work->data = reinterpret_cast<void *>(jsCallback);

    int ret = uv_queue_work_with_qos(
        loop, work, [](uv_work_t *work) {},
        [](uv_work_t *work, int status) {
            FSNapiStatusJsCallback *callback = reinterpret_cast<FSNapiStatusJsCallback *>(work->data);
            NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(callback->bundleName_);
            if (fileShareNapi == nullptr) {
                LOGE("OnDiscoveryFailed, fileShareNapi not find for bundleName %{public}s", callback->bundleName_.c_str());
            } else {
                fileShareNapi->OnDiscoveryFailed(callback->subscribeId_, callback->reason_);
            }
            DeleteFSNapiStatusJsCallbackPtr(callback);
            DeleteUvWork(work);
        },
        uv_qos_user_initiated);
    if (ret != 0) {
        LOGE("Failed to execute OnDiscoveryFailed work queue");
        DeleteFSNapiStatusJsCallbackPtr(jsCallback);
        DeleteUvWork(work);
    }
}

void FSNapiDiscoveryCallback::OnDiscoverySuccess(uint16_t subscribeId)
{
    NapiFileShare *fileShareNapi = NapiFileShare::GetFileShareNapi(bundleName_);
    if (fileShareNapi == nullptr) {
        LOGE("OnDiscoverySuccess, fileShareNapi not find for bundleName %{public}s", bundleName_.c_str());
        return;
    }
    LOGI("DiscoverySuccess for %{public}s, subscribeId %{public}d", bundleName_.c_str(), (int32_t)subscribeId);
}

void FSNapiDiscoveryCallback::IncreaseRefCount() { refCount_++; }

void FSNapiDiscoveryCallback::DecreaseRefCount() { refCount_--; }

int32_t FSNapiDiscoveryCallback::GetRefCount() { return refCount_; }

NapiFileShare *NapiFileShare::GetFileShareNapi(const std::string &bundleName)
{
    std::lock_guard<std::mutex> autoLock(g_fileShareMapMutex);
    auto iter = g_fileShareMap.find(bundleName);
    if (iter == g_fileShareMap.end()) {
        return nullptr;
    }
    return iter->second;
}

NapiFileShare::NapiFileShare(napi_env env, napi_value thisVar) : FSNativeEvent(env, thisVar)
{
    env_ = env;
}

NapiFileShare::~NapiFileShare()
{
}

napi_value NapiFileShare::EnableShare(napi_env env, napi_callback_info info)
{
    LOGI("EnableShare in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argcNum = 0;
    DmPublishInfo publishInfo;
    if (!IsSystemApp()) {
        CreateBusinessError(env, ERR_NOT_SYSTEM_APP);
        return nullptr;
    }

    bool shareStatus;
    ShareManager::GetInstance().GetShareStatus(shareStatus);
    if (shareStatus == true) {
        LOGE("EnableShare failed, already enabled.");
        return nullptr;
    }

    NAPI_CALL(env, napi_get_cb_info(env, info, &argcNum, nullptr, &thisVar, nullptr));
    if (argcNum == FS_NAPI_ARGS_ZERO) {
        publishInfo.publishId = PUBLISH_ID;
        publishInfo.mode = DmDiscoverMode::DM_DISCOVER_MODE_ACTIVE;
        publishInfo.freq = DmExchangeFreq::DM_HIGH;
        publishInfo.ranging = true;
    } else if (argcNum == FS_NAPI_ARGS_ONE) {
        GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
        napi_valuetype valueType = napi_undefined;
        napi_typeof(env, argv[FS_NAPI_ARGS_ZERO], &valueType);
        if (!CheckArgsType(env, valueType == napi_object, "publishInfo", "object")) {
            return nullptr;
        }
        JsToDmPublishInfo(env, argv[FS_NAPI_ARGS_ZERO], publishInfo);
    }

    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    int32_t ret = ShareManager::GetInstance().ChangeUuid(FILE_SHARE_UUID);
    if (ret != FS_SUCCESS) {
        LOGE("ChangeUuid failed, ret %{public}d", ret);
        return result;
    }

    std::shared_ptr<FSNapiPublishCallback> publishCallback = nullptr;
    auto iter = g_publishCallbackMap.find(shareManagerWrapper->bundleName_);
    if (iter == g_publishCallbackMap.end()) {
        publishCallback = std::make_shared<FSNapiPublishCallback>(env, shareManagerWrapper->bundleName_);
        g_publishCallbackMap[shareManagerWrapper->bundleName_] = publishCallback;
    } else {
        publishCallback = iter->second;
    }

    ret = DeviceManager::GetInstance().PublishDeviceDiscovery(shareManagerWrapper->bundleName_, publishInfo, publishCallback);
    if (ret != DM_OK) {
        LOGE("EnableShare for bundleName %{public}s failed, ret %{public}d", shareManagerWrapper->bundleName_.c_str(), ret);
        ShareManager::GetInstance().ChangeUuid(ORIGIN_UUID);
        CreateBusinessError(env, ret);
        publishCallback->OnPublishResult(publishInfo.publishId, ret);
        return result;
    }

    ShareManager::GetInstance().SetShareStatus(true);
    int32_t duration = ShareManager::GetInstance().GetWorkDuration();
    LOGD("DisableShare duration %{public}d",duration);
    napi_get_undefined(env, &result);
    return result;
}

void NapiFileShare::OnDeviceFound(uint16_t subscribeId, const DmDeviceBasicInfo &deviceBasicInfo)
{
    LOGD("OnDeviceFound DmDeviceBasicInfo for subscribeId %{public}d", (int32_t)subscribeId);

    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result = nullptr;
    napi_create_object(env_, &result);

    napi_value device = nullptr;
    napi_create_object(env_, &device);
    DmDeviceBasicToJsObject(env_, deviceBasicInfo, device);

    napi_set_named_property(env_, result, "device", device);
    OnEvent("discoverSuccess", FS_NAPI_ARGS_ONE, &result);
    napi_close_handle_scope(env_, scope);
}

void NapiFileShare::OnAuthResult(const std::string &deviceId, const std::string &token, int32_t status, int32_t reason)
{
    LOGD("OnAuthResult for status: %d, reason: %d", status, reason);
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value thisVar = nullptr;
    napi_get_reference_value(env_, thisVarRef_, &thisVar);
    napi_value result[FS_NAPI_ARGS_TWO] = {0};

    if (status == STATUS_DM_AUTH_FINISH && reason == 0) {
        LOGI("OnAuthResult success");
        napi_get_undefined(env_, &result[0]);
        napi_create_object(env_, &result[1]);
        SetValueUtf8String(env_, "deviceId", deviceId, result[1]);
    } else {
        LOGI("OnAuthResult failed");
        napi_create_object(env_, &result[0]);
        SetValueInt32(env_, "code", status, result[0]);
        SetValueInt32(env_, "reason", reason, result[0]);
        std::string errCodeInfo = OHOS::DistributedHardware::GetErrorString((int)reason);
        SetValueUtf8String(env_, "errInfo", errCodeInfo, result[0]);
        napi_get_undefined(env_, &result[1]);
    }

    if (reason == DM_OK && (status <= STATUS_DM_CLOSE_PIN_INPUT_UI && status >= STATUS_DM_SHOW_AUTHORIZE_UI)) {
        LOGI("update ui change, status: %d, reason: %d", status, reason);
    } else {
        napi_value callResult = nullptr;
        napi_value handler = nullptr;
        napi_get_reference_value(env_, authAsyncCallbackInfo_.callback, &handler);
        if (handler != nullptr) {
            napi_call_function(env_, nullptr, handler, FS_NAPI_ARGS_TWO, &result[0], &callResult);
            napi_delete_reference(env_, authAsyncCallbackInfo_.callback);
        } else {
            LOGE("handler is nullptr");
        }
        g_authCallbackMap.erase(bundleName_);
    }
    napi_close_handle_scope(env_, scope);
}

void NapiFileShare::OnDeviceStatusChange(FSNapiDevStatusChange action,
    const OHOS::DistributedHardware::DmDeviceBasicInfo &deviceBasicInfo)
{
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result = nullptr;
    napi_create_object(env_, &result);
    SetValueInt32(env_, "action", (int)action, result);

    napi_value device = nullptr;
    napi_create_object(env_, &device);
    DmDeviceBasicToJsObject(env_, deviceBasicInfo, device);

    napi_set_named_property(env_, result, "device", device);
    OnEvent("connectionChange", FS_NAPI_ARGS_ONE, &result);
    napi_close_handle_scope(env_, scope);
}

void NapiFileShare::OnDiscoveryFailed(uint16_t subscribeId, int32_t failedReason)
{
    LOGD("OnDiscoveryFailed for subscribeId %{public}d", (int32_t)subscribeId);
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result = nullptr;
    napi_create_object(env_, &result);
    SetValueInt32(env_, "reason", (int)failedReason, result);
    std::string errCodeInfo = OHOS::DistributedHardware::GetErrorString((int)failedReason);
    SetValueUtf8String(env_, "errInfo", errCodeInfo, result);
    OnEvent("discoverFailure", FS_NAPI_ARGS_ONE, &result);
    napi_close_handle_scope(env_, scope);
}

void NapiFileShare::OnPublishResult(int32_t publishId, int32_t publishResult)
{
    LOGI("OnPublishResult for publishId %{public}d, publishResult %{public}d", publishId, publishResult);
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result = nullptr;
    napi_create_object(env_, &result);
    SetValueInt32(env_, "publishId", publishId, result);
    if (publishResult == 0) {
        OnEvent("publishSuccess", FS_NAPI_ARGS_ONE, &result);
    } else {
        SetValueInt32(env_, "reason", publishResult, result);
        std::string errCodeInfo = OHOS::DistributedHardware::GetErrorString(publishResult);
        SetValueUtf8String(env_, "errInfo", errCodeInfo, result);
        OnEvent("publishFailure", FS_NAPI_ARGS_ONE, &result);
    }
    NAPI_CALL_RETURN_VOID(env_, napi_close_handle_scope(env_, scope));
}

void NapiFileShare::OnSending(SendState state, SendInfo &info)
{
    LOGD("OnSending.");
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result = nullptr;
    napi_create_object(env_, &result);

    napi_value jsInfo = nullptr;
    napi_create_object(env_, &jsInfo);
    SendInfoToJsObject(env_, info, jsInfo);

    SetValueInt32(env_, "state", (int)state, result);
    napi_set_named_property(env_, result, "info", jsInfo);

    OnEvent("sendChange", FS_NAPI_ARGS_ONE, &result);
    napi_close_handle_scope(env_, scope);
}

void NapiFileShare::OnUiCall(const std::string &paramJson)
{
    LOGD("OnCall for paramJson");
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result;
    napi_create_object(env_, &result);
    SetValueUtf8String(env_, "param", paramJson, result);
    OnEvent("authStateChange", FS_NAPI_ARGS_ONE, &result);
    napi_close_handle_scope(env_, scope);
}

void NapiFileShare::OnShareStatus(bool shareStatus)
{
    LOGD("OnShareStatus.");
    napi_handle_scope scope;
    napi_open_handle_scope(env_, &scope);
    napi_value result = nullptr;
    napi_get_boolean(env_, shareStatus, &result);

    OnEvent("shareStatusChange", FS_NAPI_ARGS_ONE, &result);
    napi_close_handle_scope(env_, scope);
}



napi_value NapiFileShare::DisableShare(napi_env env, napi_callback_info info)
{
    LOGI("DisableShare in");
    if (!IsSystemApp()) {
        CreateBusinessError(env, ERR_NOT_SYSTEM_APP);
        return nullptr;
    }

    bool shareStatus;
    ShareManager::GetInstance().GetShareStatus(shareStatus);
    if (shareStatus == false) {
        LOGE("DisableShare failed, not enable yet.");
        return nullptr;
    }

    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }

    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    int32_t ret = ShareManager::GetInstance().ChangeUuid(ORIGIN_UUID);
    if (ret != FS_SUCCESS) {
        LOGE("ChangeUuid failed, ret %{public}d", ret);
        return result;
    }

    int32_t publishId = PUBLISH_ID;
    ret = DeviceManager::GetInstance().UnPublishDeviceDiscovery(shareManagerWrapper->bundleName_, publishId);
    if (ret != DM_OK) {
        LOGE("DisableShare bundleName %{public}s failed, ret %{public}d", shareManagerWrapper->bundleName_.c_str(), ret);
        int32_t ret = ShareManager::GetInstance().ChangeUuid(FILE_SHARE_UUID);
        CreateBusinessError(env, ret);
        return result;
    }
    ShareManager::GetInstance().SetShareStatus(false);

    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::GetShareStatus(napi_env env, napi_callback_info info)
{
    LOGI("GetShareStatus in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }

    bool shareStatus;
    ShareManager::GetInstance().GetShareStatus(shareStatus);
    napi_status status = napi_get_boolean(env, shareStatus, &result);
    if (status != napi_ok) {
        LOGI("get bool error");
        return nullptr;
    }
    return result;
}

napi_value NapiFileShare::StartScan(napi_env env, napi_callback_info info)
{
    LOGI("StartScan in");
    std::string extra = "";
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argcNum = 0;
    int32_t discoverTargetType = -1;
    uint32_t subscribeId = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argcNum, nullptr, &thisVar, nullptr));

    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    if (argcNum == FS_NAPI_ARGS_ONE) {
        GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
        if (!JsToDiscoverTargetType(env, argv[FS_NAPI_ARGS_ZERO], discoverTargetType) || discoverTargetType != 1) {
            return nullptr;
        }
    } else if (argcNum == FS_NAPI_ARGS_TWO) {
        GET_PARAMS(env, info, FS_NAPI_ARGS_TWO);
        if (!JsToDiscoverTargetType(env, argv[FS_NAPI_ARGS_ZERO], discoverTargetType) || discoverTargetType != 1) {
            return nullptr;
        }
        napi_valuetype objectType = napi_undefined;
        napi_typeof(env, argv[FS_NAPI_ARGS_ONE], &objectType);
        if (!(CheckArgsType(env, objectType == napi_object, "filterOptions", "object or undefined"))) {
            return nullptr;
        }
        JsToDmDiscoveryExtra(env, argv[FS_NAPI_ARGS_ONE], extra);
    }

    int32_t ret = ShareManager::GetInstance().ChangeUuid(FILE_SHARE_UUID);
    if (ret != FS_SUCCESS) {
        LOGE("ChangeUuid failed, ret %{public}d", ret);
        return nullptr;
    }

    std::shared_ptr<FSNapiDiscoveryCallback> DiscoveryCallback = nullptr;
    auto iter = g_DiscoveryCallbackMap.find(shareManagerWrapper->bundleName_);
    if (iter == g_DiscoveryCallbackMap.end()) {
        DiscoveryCallback = std::make_shared<FSNapiDiscoveryCallback>(env, shareManagerWrapper->bundleName_);
        g_DiscoveryCallbackMap[shareManagerWrapper->bundleName_] = DiscoveryCallback;
    } else {
        DiscoveryCallback = iter->second;
    }

    DmSubscribeInfo subInfo {};
    subInfo.medium = DM_BLE;
    subInfo.subscribeId = GenRandUint(0, MAX_RANDOM);
    g_subscribeId = subInfo.subscribeId;

    ret = DeviceManager::GetInstance().StartDeviceDiscovery(shareManagerWrapper->bundleName_, subInfo, extra,
                                                                    DiscoveryCallback);
    if (ret != DM_OK) {
        LOGE("StartScan for bundleName %{public}s failed, ret %{public}d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
        DiscoveryCallback->OnDiscoveryFailed(static_cast<uint16_t>(subscribeId), ret);
    }

    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::StopScan(napi_env env, napi_callback_info info)
{
    LOGI("StopScan in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }

    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    int32_t ret = ShareManager::GetInstance().ChangeUuid(ORIGIN_UUID);
    if (ret != FS_SUCCESS) {
        LOGE("ChangeUuid failed, ret %{public}d", ret);
        return result;
    }

    ret = DeviceManager::GetInstance().StopDeviceDiscovery(shareManagerWrapper->bundleName_, g_subscribeId);
    if (ret != DM_OK) {
        LOGE("StopScan for bundleName %{public}s failed, ret %{public}d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
        return result;
    }
    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::CreateShareManager(napi_env env, napi_callback_info info)
{
    LOGI("CreateDeviceManager in");
    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc == FS_NAPI_ARGS_ONE, "Wrong number of arguments, required 1")) {
        return nullptr;
    }
    std::string bundleName;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "bundleName", bundleName)) {
        return nullptr;
    }

    std::shared_ptr<FSNapiInitCallback> initCallback = std::make_shared<FSNapiInitCallback>(env, bundleName);
    int32_t ret = DeviceManager::GetInstance().InitDeviceManager(bundleName, initCallback);
    if (ret != DM_OK) {
        LOGE("CreateDeviceManager for bundleName %{public}s failed, ret %{public}d.", bundleName.c_str(), ret);
        CreateBusinessError(env, ret);
        return nullptr;
    }
    {
        std::lock_guard<std::mutex> autoLock(g_initCallbackMapMutex);
        g_initCallbackMap[bundleName] = initCallback;
    }

    napi_value ctor = nullptr;
    napi_value napiName = nullptr;
    napi_value result = nullptr;
    napi_get_reference_value(env, sConstructor, &ctor);
    napi_create_string_utf8(env, bundleName.c_str(), NAPI_AUTO_LENGTH, &napiName);
    napi_status status = napi_new_instance(env, ctor, FS_NAPI_ARGS_ONE, &napiName, &result);
    if (status != napi_ok) {
        LOGE("Create ShareManager for bundleName %s failed", bundleName.c_str());
    }
    return result;
}

napi_value NapiFileShare::ReleaseShareManager(napi_env env, napi_callback_info info)
{
    LOGI("ReleaseDeviceManager in");
    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc == FS_NAPI_ARGS_ONE, "Wrong number of arguments, required 1")) {
        return nullptr;
    }

    napi_valuetype argvType = napi_undefined;
    napi_typeof(env, argv[FS_NAPI_ARGS_ZERO], &argvType);
    if (!CheckArgsType(env, argvType == napi_object, "ShareManager", "object")) {
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, argv[FS_NAPI_ARGS_ZERO], &shareManagerWrapper)) {
        return result;
    }

    int32_t ret = DeviceManager::GetInstance().UnInitDeviceManager(shareManagerWrapper->bundleName_);
    if (ret != DM_OK) {
        LOGE("ReleaseDeviceManager for bundleName %{public}s failed, ret %{public}d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
        return nullptr;
    }
    {
        std::lock_guard<std::mutex> autoLock(g_fileShareMapMutex);
        g_fileShareMap.erase(shareManagerWrapper->bundleName_);
    }
    {
        std::lock_guard<std::mutex> autoLock(g_initCallbackMapMutex);
        g_initCallbackMap.erase(shareManagerWrapper->bundleName_);
    }
    g_DiscoveryCallbackMap.erase(shareManagerWrapper->bundleName_);
    g_publishCallbackMap.erase(shareManagerWrapper->bundleName_);
    g_authCallbackMap.erase(shareManagerWrapper->bundleName_);
    g_deviceStatusCallbackMap.erase(shareManagerWrapper->bundleName_);
    g_sendFileCallbackMap.erase(shareManagerWrapper->bundleName_);
    g_uiCallbackMap.erase(shareManagerWrapper->bundleName_);

    napi_create_uint32(env, DM_OK, &result);
    return result;
}

napi_value NapiFileShare::Constructor(napi_env env, napi_callback_info info)
{
    LOGI("Constructor in");

    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_ONE, "Wrong number of arguments, required 1")) {
        return nullptr;
    }
    std::string bundleName;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "bundleName", bundleName)) {
        return nullptr;
    }

    NapiFileShare *obj = new (std::nothrow) NapiFileShare(env, thisVar);
    if (obj == nullptr) {
        LOGE("new NapiFileShare failed.");
        CreateBusinessError(env, ERR_DM_INIT_FAILED);
        return nullptr;
    }
    obj->bundleName_ = bundleName;
    std::lock_guard<std::mutex> autoLock(g_fileShareMapMutex);
    g_fileShareMap[obj->bundleName_] = obj;

    napi_wrap(
        env, thisVar, reinterpret_cast<void *>(obj),
        [](napi_env env, void *data, void *hint) {
            (void)env;
            (void)hint;
            NapiFileShare *shareManager = reinterpret_cast<NapiFileShare *>(data);
            delete shareManager;
            shareManager = nullptr;
            LOGI("delete shareManager");
        },
        nullptr, nullptr);
    return thisVar;
}

void NapiFileShare::BindDevice(NapiFileShare *shareManagerWrapper, const std::string &deviceId, napi_env env, napi_value &object)
{
    LOGI("BindDevice in");
    std::string bindParam;
    JsToBindParam(env, object, bindParam, authAsyncCallbackInfo_.authType);
    
    std::shared_ptr<FSNapiAuthenticateCallback> bindDeviceCallback = nullptr;
    auto iter = g_authCallbackMap.find(shareManagerWrapper->bundleName_);
    if (iter == g_authCallbackMap.end()) {
        bindDeviceCallback = std::make_shared<FSNapiAuthenticateCallback>(env, shareManagerWrapper->bundleName_);
        g_authCallbackMap[shareManagerWrapper->bundleName_] = bindDeviceCallback;
    } else {
        bindDeviceCallback = iter->second;
    }

    int32_t ret = DeviceManager::GetInstance().BindDevice(shareManagerWrapper->bundleName_, authAsyncCallbackInfo_.authType,
        deviceId, bindParam, bindDeviceCallback);        
    if (ret != DM_OK) {
        LOGE("BindDevice for bundleName %s failed, ret %d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
    }    
}

napi_value NapiFileShare::Connect(napi_env env, napi_callback_info info)
{
    LOGI("Connect in");
    GET_PARAMS(env, info, FS_NAPI_ARGS_THREE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_THREE,  "Wrong number of arguments, required 3")) {
        return nullptr;
    }

    if (!IsJSObjectType(env, argv[FS_NAPI_ARGS_ONE], "bindParam")) {
        return nullptr;
    }

    authAsyncCallbackInfo_.env = env;
    napi_create_reference(env, argv[FS_NAPI_ARGS_TWO], 1, &authAsyncCallbackInfo_.callback);
    if (!IsFunctionType(env, argv[FS_NAPI_ARGS_TWO])) {
        return nullptr;
    }

    std::string deviceId;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "deviceId", deviceId)) {
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    napi_value object = argv[FS_NAPI_ARGS_ONE];
    BindDevice(shareManagerWrapper, deviceId, env, object);
    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::Disconnect(napi_env env, napi_callback_info info)
{
    LOGI("Disconnect in");
    napi_value result = nullptr;
    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_ONE,  "Wrong number of arguments, required 1")) {
        return nullptr;
    }
    std::string deviceId;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "deviceId", deviceId)) {
        return nullptr;
    }

    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    LOGI("Disconnect deviceId = %{public}s", GetAnonyString(deviceId).c_str());

    int32_t ret = DeviceManager::GetInstance().UnBindDevice(shareManagerWrapper->bundleName_, deviceId);
    if (ret != DM_OK) {
        LOGE("UnBindDevice for bundleName %s failed, ret %d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
    }
    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::ConfirmConnect(napi_env env, napi_callback_info info)
{
    LOGI("ConfirmConnect in");
    if (!IsSystemApp()) {
        LOGI("not SystemApp");
        CreateBusinessError(env, ERR_NOT_SYSTEM_APP);
        return nullptr;
    }
    
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        LOGE("input param is not 0");
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    int32_t action = CONFIRM_CONNECT;
    std::string params = "extra";
    int32_t ret = DeviceManager::GetInstance().SetUserOperation(shareManagerWrapper->bundleName_, action, params);
    if (ret != DM_OK) {
        LOGE("SetUserOperation for bundleName %s failed, ret %d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
    }
    
    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::RefuseConnect(napi_env env, napi_callback_info info)
{
    LOGI("RefuseConnect in");
    if (!IsSystemApp()) {
        LOGI("not SystemApp");
        CreateBusinessError(env, ERR_NOT_SYSTEM_APP);
        return nullptr;
    }
    
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        LOGE("input param is not 0");
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    int32_t action = REFUSE_CONNECT;
    std::string params = "extra";
    int32_t ret = DeviceManager::GetInstance().SetUserOperation(shareManagerWrapper->bundleName_, action, params);
    if (ret != DM_OK) {
        LOGE("SetUserOperation for bundleName %s failed, ret %d", shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
    }
    
    napi_get_undefined(env, &result);
    return result;
}

void NapiFileShare::CreateFSCallback(napi_env env, const std::string &bundleName, std::string &eventType)
{
    LOGI("CreateFSCallback for bundleName %s eventType %s", bundleName.c_str(), eventType.c_str());
    if (eventType == FS_NAPI_EVENT_DEVICE_CONNECTION_CHANGE) {
        auto callback = std::make_shared<FSNapiDeviceStatusCallback>(env, bundleName);
        std::string extra = "";
        int32_t ret = DeviceManager::GetInstance().RegisterDevStatusCallback(bundleName, extra, callback);
        if (ret != DM_OK) {
            LOGE("RegisterDevStatusCallback failed for bundleName %s", bundleName.c_str());
            CreateBusinessError(env, ret);
            return;
        }
        g_deviceStatusCallbackMap.erase(bundleName);
        g_deviceStatusCallbackMap[bundleName] = callback;
        return;
    }
    if (eventType == FS_NAPI_EVENT_DEVICE_DISCOVER_SUCCESS || eventType == FS_NAPI_EVENT_DEVICE_DISCOVER_FAIL) {
        auto callback = std::make_shared<FSNapiDiscoveryCallback>(env, bundleName);
        g_DiscoveryCallbackMap.erase(bundleName);
        g_DiscoveryCallbackMap[bundleName] = callback;
        std::shared_ptr<FSNapiDiscoveryCallback> discoveryCallback = callback;
        discoveryCallback->IncreaseRefCount();
        return;
    }
    if (eventType == FS_NAPI_EVENT_DEVICE_PUBLISH_SUCCESS || eventType == FS_NAPI_EVENT_DEVICE_PUBLISH_FAIL) {
        auto callback = std::make_shared<FSNapiPublishCallback>(env, bundleName);
        g_publishCallbackMap.erase(bundleName);
        g_publishCallbackMap[bundleName] = callback;
        std::shared_ptr<FSNapiPublishCallback> publishCallback = callback;
        publishCallback->IncreaseRefCount();
        return;
    }
    if (eventType == FS_NAPI_EVENT_SEND_CHANGE) {
        auto callback = std::make_shared<FSNapiSendFileCallback>(env, bundleName);
        int32_t ret = ShareManager::GetInstance().RegisterFileShareCallback(bundleName, callback);
        if (ret != FS_SUCCESS) {
            LOGE("RegisterFileShareCallback failed for bundleName %s", bundleName.c_str());
            CreateBusinessError(env, ret);
            return;
        }
        g_sendFileCallbackMap.erase(bundleName);
        g_sendFileCallbackMap[bundleName] = callback;
    }
    if (eventType == FS_NAPI_AUTH_STATE_CHANGE) {
        auto callback = std::make_shared<FSNapiUiCallback>(env, bundleName);
        int32_t ret = DeviceManager::GetInstance().RegisterDeviceManagerFaCallback(bundleName, callback);
        if (ret != 0) {
            LOGE("RegisterDeviceManagerFaCallback failed for bundleName %s", bundleName.c_str());
            return;
        }
        g_uiCallbackMap.erase(bundleName);
        g_uiCallbackMap[bundleName] = callback;
    }
    if (eventType == FS_NAPI_EVENT_SHARE_STATUS_CHANGE) {
        auto callback = std::make_shared<FSNapiShareStatusCallback>(env, bundleName);
        int32_t ret = ShareManager::GetInstance().RegisterShareStatusCallback(bundleName, callback);
        if (ret != FS_SUCCESS) {
            LOGE("RegisterShareStatusCallback failed for bundleName %s", bundleName.c_str());
            CreateBusinessError(env, ret);
            return;
        }
        g_shareStatusCallbackMap.erase(bundleName);
        g_shareStatusCallbackMap[bundleName] = callback;
    }
}

napi_value NapiFileShare::JsOnProcess(napi_env env, int32_t num, napi_value thisVar, napi_value argv[])
{
    std::string eventType;
    if (!JsToStringAndCheck(env, argv[0], "type", eventType)) {
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    LOGI("JsOnProcess for bundleName %s, eventType %s ", shareManagerWrapper->bundleName_.c_str(), eventType.c_str());
    shareManagerWrapper->On(eventType, argv[num + FS_NAPI_ARGS_ONE]);
    CreateFSCallback(env, shareManagerWrapper->bundleName_, eventType);

    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::JsOn(napi_env env, napi_callback_info info)
{
    LOGI("JsOn in");
    int32_t ret = DeviceManager::GetInstance().CheckNewAPIAccessPermission();
    if (ret != DM_OK) {
        CreateBusinessError(env, ret);
        return nullptr;
    }
    GET_PARAMS(env, info, FS_NAPI_ARGS_TWO);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_TWO, "Wrong number of arguments, required 2")) {
        return nullptr;
    }
    napi_valuetype eventValueType = napi_undefined;
    napi_typeof(env, argv[FS_NAPI_ARGS_ZERO], &eventValueType);
    if (!CheckArgsType(env, eventValueType == napi_string, "type", "string")) {
        return nullptr;
    }
    if (!IsFunctionType(env, argv[FS_NAPI_ARGS_ONE])) {
        return nullptr;
    }
    return JsOnProcess(env, FS_NAPI_ARGS_ZERO, thisVar, argv);
}

void NapiFileShare::ReleaseFSCallback(std::string &bundleName, std::string &eventType)
{
    LOGI("ReleaseFSCallback for bundleName %s eventType %s", bundleName.c_str(), eventType.c_str());
    if (eventType == FS_NAPI_EVENT_DEVICE_CONNECTION_CHANGE) {
        auto iter = g_deviceStatusCallbackMap.find(bundleName);
        if (iter == g_deviceStatusCallbackMap.end()) {
            LOGW("ReleaseFSCallback: cannot find status callback for bundleName %s", bundleName.c_str());
            return;
        }
        int32_t ret = DeviceManager::GetInstance().UnRegisterDevStatusCallback(bundleName);
        if (ret != DM_OK) {
            LOGE("UnRegisterDevStatusCallback failed for bundleName %s", bundleName.c_str());
            return;
        }
        g_deviceStatusCallbackMap.erase(bundleName);
        return;
    }
    if (eventType == FS_NAPI_EVENT_DEVICE_DISCOVER_SUCCESS || eventType == FS_NAPI_EVENT_DEVICE_DISCOVER_FAIL) {
        auto iter = g_DiscoveryCallbackMap.find(bundleName);
        if (iter == g_DiscoveryCallbackMap.end()) {
            LOGW("ReleaseFSCallback: cannot find device discover callback for bundleName %s", bundleName.c_str());
            return;
        }
        std::shared_ptr<FSNapiDiscoveryCallback> discoveryCallback = iter->second;
        discoveryCallback->DecreaseRefCount();
        if (discoveryCallback->GetRefCount() == 0) {
            g_DiscoveryCallbackMap.erase(bundleName);
        }
        return;
    }
    if (eventType == FS_NAPI_EVENT_DEVICE_PUBLISH_SUCCESS || eventType == FS_NAPI_EVENT_DEVICE_PUBLISH_FAIL) {
        auto iter = g_publishCallbackMap.find(bundleName);
        if (iter == g_publishCallbackMap.end()) {
            LOGW("ReleaseFSCallback: cannot find device publish callback for bundleName %s", bundleName.c_str());
            return;
        }
        std::shared_ptr<FSNapiPublishCallback> publishCallback = iter->second;
        publishCallback->DecreaseRefCount();
        if (publishCallback->GetRefCount() == 0) {
            g_publishCallbackMap.erase(bundleName);
        }
        return;
    }
    if (eventType == FS_NAPI_EVENT_SEND_CHANGE) {
        auto iter = g_sendFileCallbackMap.find(bundleName);
        if (iter == g_sendFileCallbackMap.end()) {
            LOGW("ReleaseFSCallback: cannot find send file callback for bundleName %s", bundleName.c_str());
            return;
        }
        int32_t ret = ShareManager::GetInstance().UnRegisterFileShareCallback(bundleName);
        if (ret != FS_SUCCESS) {
            LOGE("UnRegisterFileShareCallback failed for bundleName %s", bundleName.c_str());
            return;
        }
        g_sendFileCallbackMap.erase(bundleName);
        return;
    }
    if (eventType == FS_NAPI_AUTH_STATE_CHANGE) {
        auto iter = g_uiCallbackMap.find(bundleName);
        if (iter == g_uiCallbackMap.end()) {
            LOGW("ReleaseFSCallback: cannot find ui callback for bundleName %s", bundleName.c_str());
            return;
        }
        int32_t ret = DeviceManager::GetInstance().UnRegisterDeviceManagerFaCallback(bundleName);
        if (ret != 0) {
            LOGE("UnRegisterDeviceManagerFaCallback failed for bundleName %s", bundleName.c_str());
            return;
        }
        g_uiCallbackMap.erase(bundleName);
        return;
    }
    if (eventType == FS_NAPI_EVENT_SHARE_STATUS_CHANGE) {
        auto iter = g_shareStatusCallbackMap.find(bundleName);
        if (iter == g_shareStatusCallbackMap.end()) {
            LOGW("ReleaseFSCallback: cannot find share status callback for bundleName %s", bundleName.c_str());
            return;
        }
        int32_t ret = ShareManager::GetInstance().UnRegisterShareStatusCallback(bundleName);
        if (ret != FS_SUCCESS) {
            LOGE("UnRegisterShareStatusCallback failed for bundleName %s", bundleName.c_str());
        }
        g_shareStatusCallbackMap.erase(bundleName);
    }
}

napi_value NapiFileShare::JsOffProcess(napi_env env, int32_t num, napi_value thisVar, napi_value argv[])
{
    std::string eventType;
    if (!JsToStringAndCheck(env, argv[0], "type", eventType)) {
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }
    shareManagerWrapper->Off(eventType);
    ReleaseFSCallback(shareManagerWrapper->bundleName_, eventType);

    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::JsOff(napi_env env, napi_callback_info info)
{
    LOGI("JsOff in");
    int32_t ret = DeviceManager::GetInstance().CheckNewAPIAccessPermission();
    if (ret != 0) {
        CreateBusinessError(env, ret);
        return nullptr;
    }

    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_ONE, "Wrong number of arguments, required 1")) {
        return nullptr;
    }
    napi_valuetype eventValueType = napi_undefined;
    napi_typeof(env, argv[FS_NAPI_ARGS_ZERO], &eventValueType);
    if (!CheckArgsType(env, eventValueType == napi_string, "type", "string")) {
        return nullptr;
    }
    return JsOffProcess(env, FS_NAPI_ARGS_ZERO, thisVar, argv);
}

napi_value NapiFileShare::SendFile(napi_env env, napi_callback_info info)
{
    LOGI("SendFile in");
    napi_value result = nullptr;
    GET_PARAMS(env, info, FS_NAPI_ARGS_THREE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_THREE,  "Wrong number of arguments, required 3")) {
        return nullptr;
    }
    std::string deviceId;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "deviceId", deviceId)) {
        return nullptr;
    }

    int32_t type = 0;
    napi_get_value_int32(env, argv[FS_NAPI_ARGS_ONE], &type);
    
    bool isArray = false;
    uint32_t arrayLength = 0;
    napi_status status = napi_is_array(env, argv[FS_NAPI_ARGS_TWO], &isArray);
    if (status != napi_ok || isArray == false) {
        LOGE("input param 2 is not array");
        return nullptr;
    }

    status = napi_get_array_length(env, argv[FS_NAPI_ARGS_TWO], &arrayLength);
    if (status != napi_ok) {
        LOGE("get array length failed");
        return nullptr;
    }
    std::vector<FSNapiFileInfo> files;
    for (size_t i = 0; i < arrayLength; i++) {
        napi_value element = nullptr;
        status = napi_get_element(env, argv[FS_NAPI_ARGS_TWO], i, &element);
        if (status != napi_ok) {
            LOGE("get element failed");
            return nullptr;
        }
        if (!IsJSObjectType(env, element, "fileInfo")) {
            return nullptr;
        }
        FSNapiFileInfo fileInfo {};
        JsToFileInfo(env, element, fileInfo);
        files.push_back(fileInfo);
    }

    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    return SendFileInner(env, (ShareType)type, deviceId, files);
}

napi_value NapiFileShare::SendFileInner(napi_env env, ShareType type, std::string &deviceId, std::vector<FSNapiFileInfo> &fsFiles)
{
    napi_value result = nullptr;
    napi_get_undefined(env, &result);

    std::vector<FileInfo> files;
    std::string folderName = FSfilesToFiles(type, fsFiles, files);
    if (type == ShareType::SAVE_AS_FOLDER && folderName.empty()) {
        LOGE("SendFile failed, folder name is empty.");
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), "folder name is empty");
        return result;
    }

    SendTask task {};
    task.type = type;
    task.deviceId = deviceId;
    task.folderName = folderName;
    task.files = std::move(files);

    int32_t ret = ShareManager::GetInstance().SendFile(task);
    if (ret != FS_SUCCESS) {
        LOGE("SendFile failed ret=%{public}d", ret);
        CreateBusinessError(env, ret);
        return result;
    }

    return result;
}

std::string NapiFileShare::FSfilesToFiles(ShareType type, std::vector<FSNapiFileInfo> &fsFiles, std::vector<FileInfo> &files)
{
    std::vector<std::string> folderNames;
    for (const auto &fsFile : fsFiles) {
        if (type == ShareType::SAVE_AS_FOLDER) {
            std::vector<std::string> tmp;
            SplitStr(fsFile.name, "/", tmp);
            if (tmp.size() == 2) {
                folderNames.push_back(tmp[0]);
            }
        }
        FileInfo fileInfo {};
        fileInfo.size = fsFile.size;
        fileInfo.uri = std::string(fsFile.uri);
        fileInfo.name = std::string(fsFile.name);
        fileInfo.utd = std::string(fsFile.utd);
        files.push_back(std::move(fileInfo));
    }
    std::string folderName = "";
    if (type == ShareType::SAVE_AS_FOLDER && !folderNames.empty() && folderNames.size() == fsFiles.size()) {
        if (std::all_of(folderNames.begin(), folderNames.end(),
            [&folderNames](const std::string &str) { return str == folderNames.front(); })) {
            folderName = folderNames[0];
        }
    }
    return folderName;
}

napi_value NapiFileShare::CancelSendFile(napi_env env, napi_callback_info info)
{
    LOGI("CancelSendFile in");
    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_ONE,  "Wrong number of arguments, required 1")) {
        return nullptr;
    }

    std::string deviceId;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "deviceId", deviceId)) {
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    SendType type = SendType::SRC;
    int32_t ret = ShareManager::GetInstance().CancelSendFile(deviceId, type);
    if (ret != FS_SUCCESS) {
        LOGE("CancelSendFile failed ret=%{public}d", ret);
        CreateBusinessError(env, ret);
        return result;
    }

    return nullptr;
}

napi_value NapiFileShare::AbortReceiveFile(napi_env env, napi_callback_info info)
{
    LOGI("AbortReceiveFile in");
    GET_PARAMS(env, info, FS_NAPI_ARGS_ONE);
    if (!CheckArgsCount(env, argc >= FS_NAPI_ARGS_ONE,  "Wrong number of arguments, required 1")) {
        return nullptr;
    }

    std::string deviceId;
    if (!JsToStringAndCheck(env, argv[FS_NAPI_ARGS_ZERO], "deviceId", deviceId)) {
        return nullptr;
    }

    napi_value result = nullptr;
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return result;
    }

    SendType type = SendType::SINK;
    int32_t ret = ShareManager::GetInstance().CancelSendFile(deviceId, type);
    if (ret != FS_SUCCESS) {
        LOGE("SendFile failed ret=%{public}d", ret);
        CreateBusinessError(env, ret);
        return result;
    }

    return nullptr;
}

napi_value NapiFileShare::GetShareStoragePath(napi_env env, napi_callback_info info)
{
    LOGI("GetShareStoragePath in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }
    std::string path = ShareManager::GetInstance().GetStoragePath();
    if (path == "") {
        LOGE("path not exsit!");
        return nullptr;
    }
    napi_status status = napi_create_string_utf8(env, path.c_str(), path.length(), &result);
    if (status != napi_ok) {
        LOGE("create string error");
        return nullptr;
    }
    return result;
}

napi_value NapiFileShare::SetShareStoragePath(napi_env env, napi_callback_info info)
{
    LOGI("SetStoragePath in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    napi_value argv[FS_NAPI_ARGS_ONE] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ONE) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
    ASSERT_AND_THROW_PARAM_ERROR(env, MatchValueType(env, argv[FS_NAPI_ARGS_ZERO], napi_string), "parameter must be string");
    std::string path;
    ASSERT_AND_THROW_PARAM_ERROR(env, GetStringFromJS(env, argv[FS_NAPI_ARGS_ZERO], path), "string parameter error");
    if (path == "") {
        ASSERT_AND_THROW_PARAM_ERROR(env, path != "","path can not be null");
        return nullptr;
    }
    int32_t ret = ShareManager::GetInstance().SetStoragePath(path);
    if(ret != FS_SUCCESS){
        return nullptr;
    }
    LOGI("SetStoragePath success");
    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::GetShareOpenTime(napi_env env, napi_callback_info info)
{
    LOGI("GetShareOpenTime in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ZERO) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }
    int32_t time =ShareManager::GetInstance().GetWorkDuration();
    napi_status status = napi_create_int32(env, time, &result);
    if (status != napi_ok) {
        LOGE("create number error");
        return nullptr;
    }
    LOGI("GetShareOpenTime success");
    return result;
}

napi_value NapiFileShare::SetShareOpenTime(napi_env env, napi_callback_info info)
{
    LOGI("SetShareOpenTime in");
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    napi_value argv[FS_NAPI_ARGS_ONE] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    if (argc != FS_NAPI_ARGS_ONE) {
        CreateBusinessError(env, ERR_DM_INPUT_PARA_INVALID);
        return nullptr;
    }
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
    ASSERT_AND_THROW_PARAM_ERROR(env, MatchValueType(env, argv[FS_NAPI_ARGS_ZERO], napi_number), "parameter must be number");
    int32_t time;
    ASSERT_AND_THROW_PARAM_ERROR(env, GetNumberFromJS(env, argv[FS_NAPI_ARGS_ZERO], time), "number parameter error");
    if (time <0) {
        ASSERT_AND_THROW_PARAM_ERROR(env, time >=0, "time can not be < 0");
        return nullptr;
    }
    int32_t ret = ShareManager::GetInstance().SetWorkDuration(time);
    if(ret != FS_SUCCESS){
        return nullptr;
    }
    LOGI("SetShareOpenTime success");
    napi_get_undefined(env, &result);
    return result;
}

napi_value NapiFileShare::GetAvailableDeviceList(napi_env env, napi_callback_info info)
{
    LOGI("GetAvailableDeviceList in");
    int32_t ret = DeviceManager::GetInstance().CheckNewAPIAccessPermission();
    if (ret != 0) {
        CreateBusinessError(env, ret);
        return nullptr;
    }
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc = 0;
    bool isArray = false;
    napi_create_array(env, &result);
    napi_is_array(env, result, &isArray);
    if (!isArray) {
        LOGE("napi_create_array fail");
        return nullptr;
    }

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
    NapiFileShare *shareManagerWrapper = nullptr;
    if (IsShareManagerNapiNull(env, thisVar, &shareManagerWrapper)) {
        return nullptr;
    }

    std::vector<DmDeviceBasicInfo> devList;
    ret = DeviceManager::GetInstance().GetAvailableDeviceList(shareManagerWrapper->bundleName_, devList);
    if (ret != DM_OK) {
        LOGE("GetTrustedDeviceList for bundleName %{public}s failed, ret %{public}d",
            shareManagerWrapper->bundleName_.c_str(), ret);
        CreateBusinessError(env, ret);
        return result;
    }

    for (size_t i = 0; i < devList.size(); ++i) {
        DeviceBasicInfoToJsArray(env, devList, (int32_t)i, result);
    }

    return result;
}
} // namespace FileShare
} // namespace OHOS